package com.cmes.core.context;

import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.lang.NonNull;

/**
 * Spring ApplicationContext 上下文
 *
 * @author Bruce.Gong
 * @since 1.0.0-SNAPSHOT
 */
@Slf4j
public class SpringContextHolder implements ApplicationContextAware, DisposableBean {

    private static ApplicationContext applicationContext;

    @SuppressWarnings("unchecked")
    public static <T> T getBean(String beanName) {
        checkApplicationContext();
        return (T) applicationContext.getBean(beanName);
    }

    public static <T> T getBean(Class<T> className) {
        checkApplicationContext();
        return applicationContext.getBean(className);
    }

    public static <T> T getBean(String beanName, Class<T> className) {
        checkApplicationContext();
        return applicationContext.getBean(beanName, className);
    }

    public static void clearApplicationContext() {
        applicationContext = null;
    }

    public static void checkApplicationContext() {
        if (applicationContext == null) {
            throw new IllegalStateException("applicationContext未注入，请在Spring配置文件中进行注册!");
        }
    }

    public static ApplicationContext getApplicationContext() {
        checkApplicationContext();
        return applicationContext;
    }

    @Override
    public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
        if (SpringContextHolder.applicationContext != null) {
            log.warn("Refreshing ApplicationContext in SpringContextHolder");
        } else {
            log.info("Initializing ApplicationContext into SpringContextHolder");
        }
        SpringContextHolder.applicationContext = applicationContext;
    }

    /**
     * 发布事件
     *
     * @param event 事件
     */
    public static void publishEvent(ApplicationEvent event) {
        checkApplicationContext();
        applicationContext.publishEvent(event);
    }

    @Override
    public void destroy() throws Exception {
        clearApplicationContext();
    }

    /**
     * 获取aop代理对象
     *
     * @return 代理对象
     */
    @SuppressWarnings("unchecked")
    public static <T> T getCurrentProxy() {
        return (T) AopContext.currentProxy();
    }

}
